#include <stdio.h>
#include <stdlib.h>
#include "linphone/linphonecore.h"
#include "smartphonecore.h"


static LinphoneCore *g_linphonec = NULL;
static SmartphoneCallback g_callback = NULL;
static SmartphoneLogFunc g_log_func = NULL;

static LinphoneCoreVTable g_linphonec_vtable = {0};
char record_path[128];

static LinphoneAddress *
smartphone_address_new(const char *addr)           //地址转化为标准sip address("sip:"或者"sips:"开头)
{
    LinphoneAddress *address = NULL;
    char *modified = NULL;
    if (strstr(addr, "sip:") == NULL && strstr(addr, "sips:") == NULL) {
        modified = ms_strdup_printf("sip:%s", addr);
        address = linphone_address_new(modified);
        ms_free(modified);
    }
    if (address == NULL) {
        address = linphone_address_new(addr);
    }
    return address;
}

static int is_valid_ip(const char *ip) {
    if (ip == NULL)
        return 0;
    char temp[4];
    int count = 0;
    while (1) {
        int index = 0;
        while (*ip != '\0' && *ip != '.' && count < 4) {
            temp[index++] = *ip;
            ip++;
            if (index == 4)
                return 0;
        }

        temp[index] = '\0';
        int num = atoi(temp);
        if (!(num >= 0 && num <= 255))
            return 0;
        count++;
        if (*ip == '\0') {
            if (count == 4)
                return 1;
            else
                return 0;
        } else
            ip++;
    }
    return 1;
}

static char *add_sip_prefix_to_ip(const char *ip)      //将标准ip v4地址添加sip:或sips:前缀
{
    char *modified_ip = NULL;
    LinphoneAddress *address = NULL;
    address = smartphone_address_new(ip);
    modified_ip = linphone_address_as_string(address);
    linphone_address_unref(address);
    return modified_ip;
}

static int set_call_identity(LinphoneCall *call) {
    static long callid = 0;
    callid++;
    if (callid > 100000)
        callid = 1;
    linphone_call_set_user_pointer(call, (void *) callid);

    return callid;
}

static LinphoneCall *get_call_by_callid(long callid) {
    LinphoneCall *call = NULL;
    MSList *call_list = NULL;
    if (linphone_core_get_calls_nb(g_linphonec) < 1) {
        return NULL;
    }
    call_list = (MSList *) linphone_core_get_calls(g_linphonec);
    do {
        call = (LinphoneCall *) call_list->data;
        if (call) {
            if (callid == (long) linphone_call_get_user_pointer(call)) {
                return call;
            }
        }

    } while ((call_list = call_list->next) != NULL);
    return NULL;
}

static void add_authinfo(LinphoneAddress *address, const char *passwd) {
    if (address != NULL) {
        LinphoneAuthInfo *authInfo = linphone_auth_info_new(linphone_address_get_username(address),
                                                            NULL, passwd, NULL, NULL,
                                                            linphone_address_get_domain(address));
        linphone_core_add_auth_info(g_linphonec, authInfo);
        linphone_auth_info_destroy(authInfo);
    }
}

void
smartphone_global_state_changed(LinphoneCore *lc, LinphoneGlobalState gstate, const char *message) {
    //ms_warning("smartphone_global_state_changed---------> message = %s\n", message);
}

void smartphone_registration_state_changed(LinphoneCore *lc, LinphoneProxyConfig *cfg,
                                           LinphoneRegistrationState rstate, const char *message) {
    ms_warning("smartphone_registration_state_changed---------> message = %s\n", message);
    SmartphoneCallbackParam param;
    RegistrationStateInfo regInfo;

    memset(&regInfo, 0, sizeof(regInfo));
    strcpy(regInfo.proxy, linphone_proxy_config_get_addr(cfg));
    regInfo.message = message;

    param.state = rstate;
    param.data = &regInfo;

    if (g_callback) {
        g_callback(&param);
    }

}

void smartphone_call_state_changed(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState cstate,
                                   const char *message) {

    ms_warning("smartphone_call_state_changed---------> message = %s", message);
    ms_warning("smartphone call state reason = %s", linphone_call_state_to_string(cstate));
    SmartphoneCallbackParam param;
    CallStateInfo callInfo;
    memset(&callInfo, 0, sizeof(callInfo));
    const LinphoneAddress *remote_address = linphone_call_get_remote_address(call);
    const char *tmp = linphone_address_get_username(remote_address);
    if (tmp)
        strcpy(callInfo.username, tmp);
    tmp = linphone_address_get_display_name(remote_address);
    if (tmp)
        strcpy(callInfo.dispname, tmp);
    callInfo.callid = (long) linphone_call_get_user_pointer(call);
    callInfo.message = message;

    param.state = cstate + 5;
    switch (cstate) {
        case LinphoneCallIncomingReceived: {

            long callid = set_call_identity(call);

            callInfo.callid = callid;
            break;
        }
        case LinphoneCallOutgoingInit: {

            long callid = set_call_identity(call);
            callInfo.callid = callid;
            break;
        }
        default:
            break;
    }
    param.data = &callInfo;
    if (g_callback) {
        g_callback(&param);
    }

}

void smartphone_notify_presence_received(LinphoneCore *lc, LinphoneFriend *lf) {
    ms_warning("smartphone_notify_presence_received!--------->\n");
}

void smartphone_notify_presence_received_for_uri_or_tel(LinphoneCore *lc, LinphoneFriend *lf,
                                                        const char *uri_or_tel,
                                                        const LinphonePresenceModel *presence_model) {
    ms_warning("smartphone_notify_presence_received_for_uri_or_tel!--------->\n");
}

void smartphone_new_subscription_requested(LinphoneCore *lc, LinphoneFriend *lf, const char *url) {
    ms_warning("smartphone_new_subscription_requested---------> url = %s\n", url);
}

void smartphone_authentication_requested(LinphoneCore *lc, LinphoneAuthInfo *auth_info,
                                         LinphoneAuthMethod method) {
    ms_warning("smartphone_authentication_requested--------->");
}

void smartphone_call_log_updated(LinphoneCore *lc, LinphoneCallLog *newcl) {
    ms_warning("smartphone_call_log_updated--------->");
}

void smartphone_message_received(LinphoneCore *lc, LinphoneChatRoom *room,
                                 LinphoneChatMessage *message) {
    ms_warning("smartphone_message_received--------->");
    ms_warning("message = %s", linphone_chat_message_get_text(message));
    /*ms_warning("room userdata = %d", linphone_chat_room_get_user_data(room));*/
    /*ms_warning("peer = %s", room->peer);*/
    /*ms_warning("size = %d", bctbx_list_size(list));*/

}

void smartphone_is_composing_received(LinphoneCore *lc, LinphoneChatRoom *room) {
    ms_warning("smartphone_is_composing_received--------->");
}

void smartphone_dtmf_received(LinphoneCore *lc, LinphoneCall *call, int dtmf) {
    ms_warning("smartphone_dtmf_received--------->");
}

void smartphone_refer_received(LinphoneCore *lc, const char *refer_to) {
    ms_warning("smartphone_refer_received--------->");
}

void smartphone_call_encryption_changed(LinphoneCore *lc, LinphoneCall *call, bool_t on,
                                        const char *authentication_token) {
    ms_warning("smartphone_call_encryption_changed--------->");
}

void smartphone_transfer_state_changed(LinphoneCore *lc, LinphoneCall *transfered,
                                       LinphoneCallState new_call_state) {
    ms_warning("smartphone_transfer_state_changed--------->");
}

void smartphone_buddy_info_updated(LinphoneCore *lc, LinphoneFriend *lf) {
    ms_warning("smartphone_buddy_info_updated--------->");
}

void smartphone_call_stats_updated(LinphoneCore *lc, LinphoneCall *call,
                                   const LinphoneCallStats *stats) {
//    ms_warning("smartphone_call_stats_updated--------->");
}

void smartphone_info_received(LinphoneCore *lc, LinphoneCall *call, const LinphoneInfoMessage *in) {
    ms_warning("smartphone_info_received--------->");
    SmartphoneCallbackParam param;
    CallInfo callInfo;
    memset(&callInfo, 0, sizeof(callInfo));

    callInfo.callid = (long) linphone_call_get_user_pointer(call);
    const LinphoneContent *content = linphone_info_message_get_content(in);
    char *info = (char *) linphone_content_get_buffer(content);
    strcpy(callInfo.info, info);
    ms_warning("info = %s", info);
    param.state = SmartphoneCallInfoReceived;
    param.data = &callInfo;
    if (g_callback) {
        g_callback(&param);
    }
}

void smartphone_subscription_state_changed(LinphoneCore *lc, LinphoneEvent *lev,
                                           LinphoneSubscriptionState state) {
    ms_warning("smartphone_subscription_state_changed--------->");
}

void smartphone_notify_received(LinphoneCore *lc, LinphoneEvent *lev, const char *notified_event,
                                const LinphoneContent *body) {
    ms_warning("smartphone_notify_received--------->");
}

void
smartphone_publish_state_changed(LinphoneCore *lc, LinphoneEvent *lev, LinphonePublishState state) {
    ms_warning("smartphone_publish_state_changed--------->");
}

void smartphone_configuring_status(LinphoneCore *lc, LinphoneConfiguringState status,
                                   const char *message) {
    ms_warning("smartphone_configuring_status--------->");
}

void smartphone_network_reachable(LinphoneCore *lc, bool_t reachable) {
    ms_warning("smartphone_network_reachable--------->");
}

void smartphone_log_collection_upload_state_changed(LinphoneCore *lc,
                                                    LinphoneCoreLogCollectionUploadState state,
                                                    const char *info) {
    ms_warning("smartphone_log_collection_upload_state_changed--------->");
}

void smartphone_log_collection_upload_progress_indication(LinphoneCore *lc, size_t offset,
                                                          size_t total) {
    ms_warning("smartphone_log_collection_upload_progress_indication--------->");
}

void smartphone_friend_list_created(LinphoneCore *lc, LinphoneFriendList *list) {
    ms_warning("smartphone_friend_list_created--------->");
}

void smartphone_friend_list_removed(LinphoneCore *lc, LinphoneFriendList *list) {
    ms_warning("smartphone_friend_list_removed--------->");
}

static void
smartphone_log_func(const char *domain, OrtpLogLevel lev, const char *fmt, va_list args) {
    if (g_log_func != NULL) {
        g_log_func((SmartphoneLogLevel) lev, fmt, args);

    }
}

void smartphone_iterate() {
    linphone_core_iterate(g_linphonec);
}

int smartphone_init(SmartphoneCallback callback, SmartphoneLogFunc log_func) {
    g_linphonec_vtable.global_state_changed = smartphone_global_state_changed;
    g_linphonec_vtable.registration_state_changed = smartphone_registration_state_changed;
    g_linphonec_vtable.call_state_changed = smartphone_call_state_changed;
    g_linphonec_vtable.notify_presence_received = smartphone_notify_presence_received;
    g_linphonec_vtable.notify_presence_received_for_uri_or_tel = smartphone_notify_presence_received_for_uri_or_tel;
    g_linphonec_vtable.new_subscription_requested = smartphone_new_subscription_requested;
    g_linphonec_vtable.authentication_requested = smartphone_authentication_requested;
    g_linphonec_vtable.call_log_updated = smartphone_call_log_updated;
    g_linphonec_vtable.message_received = smartphone_message_received;
    g_linphonec_vtable.is_composing_received = smartphone_is_composing_received;
    g_linphonec_vtable.dtmf_received = smartphone_dtmf_received;
    g_linphonec_vtable.refer_received = smartphone_refer_received;
    g_linphonec_vtable.call_encryption_changed = smartphone_call_encryption_changed;
    g_linphonec_vtable.transfer_state_changed = smartphone_transfer_state_changed;
    g_linphonec_vtable.buddy_info_updated = smartphone_buddy_info_updated;
    g_linphonec_vtable.call_stats_updated = smartphone_call_stats_updated;
    g_linphonec_vtable.info_received = smartphone_info_received;
    g_linphonec_vtable.subscription_state_changed = smartphone_subscription_state_changed;
    g_linphonec_vtable.notify_received = smartphone_notify_received;
    g_linphonec_vtable.publish_state_changed = smartphone_publish_state_changed;
    g_linphonec_vtable.configuring_status = smartphone_configuring_status;
    g_linphonec_vtable.network_reachable = smartphone_network_reachable;
    g_linphonec_vtable.log_collection_upload_state_changed = smartphone_log_collection_upload_state_changed;
    g_linphonec_vtable.log_collection_upload_progress_indication = smartphone_log_collection_upload_progress_indication;
    g_linphonec_vtable.friend_list_created = smartphone_friend_list_created;
    g_linphonec_vtable.friend_list_removed = smartphone_friend_list_removed;

    g_linphonec = linphone_core_new(&g_linphonec_vtable, NULL, NULL, NULL);

    if (g_linphonec == NULL) {
        ms_error("g_linphonec new failed!\n");
        return -1;
    }
    linphone_core_set_sip_port(g_linphonec, 5060);
    linphone_core_enable_ipv6(g_linphonec, FALSE);
    g_log_func = log_func;
    g_callback = callback;
    linphone_core_enable_logs_with_cb(smartphone_log_func);
    linphone_core_set_log_level(ORTP_WARNING);

    linphone_core_set_network_reachable(g_linphonec, TRUE);


    return 0;
}

void smartphone_uninit() {
    if (g_linphonec) {
        linphone_core_destroy(g_linphonec);
        g_linphonec = NULL;
    }
}

int smartphone_register(const char *server_addr, SmartphoneTransportType portType,
                        const char *dispname, const char *username, const char *passwd,
                        int expires) {

    LinphoneProxyConfig *cfg = NULL;
    char *identity = NULL;
    const bctbx_list_t *elem = NULL;
    if(server_addr == NULL)
        return -1;
    LinphoneAddress *address = smartphone_address_new(server_addr);

    if (address == NULL)
        return -1;
    if (dispname)
        linphone_address_set_display_name(address, dispname);
    if (username)
        linphone_address_set_username(address, username);
    linphone_address_set_transport(address,
                                   (LinphoneTransportType) portType);      //设置通讯协议：udp, tcp, tls, dtls
    identity = linphone_address_as_string(address);
    add_authinfo(address, passwd);
    elem = linphone_core_get_proxy_config_list(g_linphonec);
    if (elem) {
        cfg = ((LinphoneProxyConfig *) elem->data);
        linphone_proxy_config_edit(cfg);
        linphone_proxy_config_set_identity(cfg, identity);
        linphone_proxy_config_set_server_addr(cfg, server_addr);
        linphone_proxy_config_enable_register(cfg, TRUE);
        linphone_proxy_config_set_expires(cfg, expires);
        linphone_proxy_config_done(cfg);
    } else {
        cfg = linphone_proxy_config_new();
        linphone_proxy_config_set_identity(cfg, identity);
        linphone_proxy_config_set_server_addr(cfg, server_addr);
        linphone_proxy_config_enable_register(cfg, TRUE);
        linphone_proxy_config_set_expires(cfg, expires);
        linphone_core_add_proxy_config(g_linphonec, cfg);
    }

    linphone_core_set_default_proxy_config(g_linphonec, cfg);

    ms_free(identity);
    linphone_address_unref(address);
    return 0;

}

void smartphone_unregister() {
    LinphoneProxyConfig *cfg = linphone_core_get_default_proxy_config(g_linphonec);
    if (cfg && linphone_proxy_config_is_registered(cfg)) {
        linphone_proxy_config_edit(cfg);
        linphone_proxy_config_enable_register(cfg, FALSE);
        linphone_proxy_config_done(cfg);

    }
}

void smartphone_refresh_registers() {
    linphone_core_refresh_registers(g_linphonec);
}


void smartphone_call(const char *identity, MediaType mt) {
    LinphoneCall *call;
    char *url = NULL;
    char *modified_username = NULL;
    LinphoneAddress *address = NULL;
    LinphoneCallParams *cp = NULL;
    if (linphone_core_in_call(g_linphonec)) {
        ms_warning("Terminate or hold on the current call first!");
        return;
    }
    if (is_valid_ip(identity))        //判断是否是ip地址
    {
        modified_username = add_sip_prefix_to_ip(identity);
        address = linphone_core_interpret_url(g_linphonec, modified_username);
        ms_free(modified_username);
    } else {
        ms_warning("smartphone_call:identity = %s\n", identity);
        address = linphone_core_interpret_url(g_linphonec, identity);
        if (address == NULL) {
            ms_warning("can not interpret identity!");
            return;
        }
    }
    ms_warning("start a call...%s", identity);
    cp = linphone_core_create_call_params(g_linphonec, NULL);
    linphone_call_params_set_record_file(cp, record_path);
    switch (mt) {
        case MediaTypeAudio:
            linphone_call_params_enable_audio(cp, TRUE);
            linphone_call_params_enable_video(cp, FALSE);
            break;
        case MediaTypeVideo:
            linphone_call_params_enable_audio(cp, FALSE);
            linphone_call_params_enable_video(cp, TRUE);
            break;
        case MediaTypeAudioVideo:
            linphone_call_params_enable_audio(cp, TRUE);
            linphone_call_params_enable_video(cp, TRUE);
            break;
    }

    url = linphone_address_as_string(address);

    if (NULL == (call = linphone_core_invite_with_params(g_linphonec, url, cp))) {
        ms_error("Error from linphone-core-invite-with-params!");
        return;
    }

    linphone_call_params_unref(cp);
    ms_free(url);
    linphone_address_unref(address);
}

void smartphone_answer(long callid, MediaType mt) {
    LinphoneCall *call = NULL;
    LinphoneCallState state;
    LinphoneCallParams *cp = NULL;

    call = get_call_by_callid(callid);
    if (call == NULL) {
        ms_warning("This is no call with callid %ld to answer!", callid);
        return;
    }
    state = linphone_call_get_state(call);
    if (state == LinphoneCallIncomingReceived || state == LinphoneCallIncomingEarlyMedia) {
        cp = linphone_core_create_call_params(g_linphonec, call);
        linphone_call_params_set_record_file(cp, record_path);

        switch (mt) {
            case MediaTypeAudio:
                linphone_call_params_enable_audio(cp, TRUE);
                linphone_call_params_enable_video(cp, FALSE);
                break;
            case MediaTypeVideo:
                linphone_call_params_enable_audio(cp, FALSE);
                linphone_call_params_enable_video(cp, TRUE);
                break;
            case MediaTypeAudioVideo:
                linphone_call_params_enable_audio(cp, TRUE);
                linphone_call_params_enable_video(cp, TRUE);
                break;
        }

        linphone_core_accept_call_with_params(g_linphonec, call, cp);

    } else {
        ms_warning("cannot answer call with callid %ld!", callid);
        return;
    }
    linphone_call_params_unref(cp);
}

void smartphone_terminate(long callid) {
    LinphoneCall *call = NULL;
    call = get_call_by_callid(callid);
    if (call == NULL) {
        ms_warning("This is no call with callid %ld to terminate!", callid);
        return;
    }
    if (LinphoneCallEnd != linphone_call_get_state(call)) {
        linphone_core_terminate_call(g_linphonec, call);
    }
    return;
}
int smartphone_call_video_enabled(long callid){
    LinphoneCall *call = get_call_by_callid(callid);
    if(call == NULL) return 0;
    const LinphoneCallParams *cp = linphone_call_get_current_params(call);
    return (int)linphone_call_params_video_enabled(cp);
}
int smartphone_get_calls_nb() {
    return linphone_core_get_calls_nb(g_linphonec);
}

void smartphone_send_info(const char *message, long callid) {
    LinphoneCall *call;
    LinphoneInfoMessage *info;
    LinphoneContent *content;
    call = get_call_by_callid(callid);
    if (call == NULL) return;
    info = linphone_core_create_info_message(g_linphonec);
    if (info == NULL) return;
    content = linphone_core_create_content(g_linphonec);
    linphone_content_set_type(content, "application");
    linphone_content_set_subtype(content, "text");
    linphone_content_set_buffer(content, (void *) message, strlen(message));
    linphone_info_message_set_content(info, content);

    linphone_call_send_info_message(call, info);

    linphone_content_unref(content);
    linphone_info_message_destroy(info);
}

void smartphone_send_message(char *username, char *msg) {
    LinphoneChatRoom *room = NULL;
    LinphoneChatMessage *message = NULL;
    LinphoneChatMessageState cs;
    room = linphone_core_get_chat_room_from_uri(g_linphonec, username);
    /*ms_warning("size = %d", bctbx_list_size(list));*/
    if (room == NULL) {
        ms_warning("failed to create chat room");
    } else {
        ms_warning("create chat success!");
        linphone_chat_room_set_user_data(room, (void *) 323);
        message = linphone_chat_room_create_message(room, msg);
        const LinphoneAddress *addr = linphone_chat_message_get_from_address(message);
        if (addr != NULL)
            ms_warning("from = %s", linphone_address_as_string(addr));
        linphone_chat_message_set_from_address(message,
                                               linphone_address_new("sip:from@192.168.1.110"));

        cs = linphone_chat_message_get_state(message);
        ms_warning("chat message state0 = %s", linphone_chat_message_state_to_string(cs));
        linphone_chat_room_send_chat_message(room, message);
        cs = linphone_chat_message_get_state(message);
        ms_warning("chat message state1 = %s", linphone_chat_message_state_to_string(cs));
    }

    ms_usleep(2000000);
    cs = linphone_chat_message_get_state(message);
    ms_warning("chat message state2 = %s", linphone_chat_message_state_to_string(cs));
}

void smartphone_set_record_file(const char *path) {
    strcpy(record_path, path);
}

void smartphone_start_recording() {
    LinphoneCall *call = linphone_core_get_current_call(g_linphonec);
    if (call != NULL)
        linphone_call_start_recording(call);
}

void smartphone_stop_recording() {
    LinphoneCall *call = linphone_core_get_current_call(g_linphonec);
    if (call != NULL)
        linphone_call_stop_recording(call);
}

void smartphone_take_preview_snapshot(long callid, const char *path) {
    LinphoneCall *call = linphone_core_get_current_call(g_linphonec);
    linphone_call_take_video_snapshot(call, path);
}

void smartphone_set_ring(const char *ring)                //设置被呼叫者的铃声
{
    linphone_core_set_ring(g_linphonec, ring);

}

void smartphone_set_ringback(char *ringback)         //设置呼叫者呼叫时的提示音，一般为嘟嘟声
{
    linphone_core_set_ringback(g_linphonec, ringback);
}

void smartphone_set_remote_ringback(char *remote_ringback)     //设置呼叫者回铃音， 类似彩铃
{
    linphone_core_set_remote_ringback_tone(g_linphonec, remote_ringback);
}

void smartphone_set_static_picture(const char *picture) {
    linphone_core_set_static_picture(g_linphonec, picture);
}

void smartphone_set_static_picture_fps(int fps) {
    linphone_core_set_static_picture_fps(g_linphonec, (float) fps);

}

void smartphone_set_native_window_id(long id) {
    linphone_core_set_native_video_window_id(g_linphonec, (void*)id);
}
long smartphone_get_native_window_id(){
    return (long)linphone_core_get_native_video_window_id(g_linphonec);
}
void smartphone_set_native_preview_window_id(long id) {
    linphone_core_set_native_preview_window_id(g_linphonec, (void*)id);
    linphone_core_use_preview_window(g_linphonec, FALSE);

}
long smartphone_get_native_preview_window_id(){
    return (long)linphone_core_get_native_preview_window_id(g_linphonec);
}

float get_audio_download_bandwith() {
    LinphoneCall *call = linphone_core_get_current_call(g_linphonec);
    const LinphoneCallStats *stats = linphone_call_get_audio_stats(call);
    return linphone_call_stats_get_download_bandwidth(stats);
}

float get_audio_upload_bandwith() {
    LinphoneCall *call = linphone_core_get_current_call(g_linphonec);
    const LinphoneCallStats *stats = linphone_call_get_audio_stats(call);
    return linphone_call_stats_get_upload_bandwidth(stats);
}

void smartphone_reload_ms_plugins(const char *path) {
    linphone_core_reload_ms_plugins(g_linphonec, path);

}

int smartphone_get_video_device_size() {
    const char **devices = linphone_core_get_video_devices(g_linphonec);
    if (devices == NULL) {
        ms_warning("No existing video devices\n");
        return 0;
    }
    int i = 0;
    while (devices[i] != NULL) {
        i++;
    }
    return i;
}

const char *smartphone_get_video_device_name(int id) {
    const char **devices = linphone_core_get_video_devices(g_linphonec);
    if (devices == NULL) {
        ms_warning("No existing video devices\n");
        return NULL;
    }
    int i = 0;
    while (devices[i] != NULL) {
        if (i == id)
            return devices[i];
        i++;
    }
    return NULL;
}

void smartphone_set_video_device(const char *name) {
            linphone_core_set_video_device(g_linphonec, name);
}

int smartphone_get_supported_video_size(){
    const MSVideoSizeDef *sizes = linphone_core_get_supported_video_sizes(g_linphonec);
    int i = 0;
    while (sizes[i].name != NULL) {
        i++;
    }
    return i;
}
const char *smartphone_get_supported_video_size_name(int id){
    const MSVideoSizeDef *sizes = linphone_core_get_supported_video_sizes(g_linphonec);
    int i = 0;
    while (sizes[i].name != NULL) {
        if(i == id)
            return sizes[i].name;
        i++;
    }
    return NULL;
}
void smartphone_set_preferred_video_size(const char *name){
    linphone_core_set_preferred_video_size_by_name(g_linphonec, name);
}

void smartphone_set_primary_contact(const char *dispname, const char *username){
    LinphoneAddress *address = linphone_core_get_primary_contact_parsed(g_linphonec);
    if (address == NULL) return;
    if(dispname)
        linphone_address_set_display_name(address, dispname);
    if (username)
        linphone_address_set_username(address, username);
    linphone_core_set_primary_contact(g_linphonec, linphone_address_as_string(address));
}


void smartphone_enable_echo_cancellation(int enabled){
    linphone_core_enable_echo_cancellation(g_linphonec, enabled);
}
void smartphone_enable_adaptive_rate_control(int enabled){
    linphone_core_enable_adaptive_rate_control(g_linphonec, enabled);
}

void smartphone_set_local_port(int port){
    linphone_core_set_sip_port(g_linphonec, port);
}
int smartphone_get_codec_size(CodecType ct) {
    int index = 0;
    const bctbx_list_t *node = NULL;
    if (ct == CodecTypeAudio)
        node = linphone_core_get_audio_codecs(g_linphonec);
    else if (ct == CodecTypeVideo)
        node = linphone_core_get_video_codecs(g_linphonec);
    else if (ct == CodecTypeText)
        node = linphone_core_get_text_codecs(g_linphonec);
    for (; node != NULL; node = bctbx_list_next(node)) {
        index++;
    }
    return index;
}

const char *smartphone_get_codec_name(CodecType ct, int id) {
    PayloadType *pt;
    int index = 0;
    const bctbx_list_t *node = NULL;
    if (ct == CodecTypeAudio)
        node = linphone_core_get_audio_codecs(g_linphonec);
    else if (ct == CodecTypeVideo)
        node = linphone_core_get_video_codecs(g_linphonec);
    else if (ct == CodecTypeText)
        node = linphone_core_get_text_codecs(g_linphonec);
    for (; node != NULL; node = bctbx_list_next(node)) {
        pt = (PayloadType *) node->data;
        if (index == id)
            return pt->mime_type;
        index++;
    }
    return NULL;
}
 int smartphone_get_codec_clock_rate(CodecType ct, int id) {
    PayloadType *pt;
    int index = 0;
    const bctbx_list_t *node = NULL;
    if (ct == CodecTypeAudio)
        node = linphone_core_get_audio_codecs(g_linphonec);
    else if (ct == CodecTypeVideo)
        node = linphone_core_get_video_codecs(g_linphonec);
    else if (ct == CodecTypeText)
        node = linphone_core_get_text_codecs(g_linphonec);
    for (; node != NULL; node = bctbx_list_next(node)) {
        pt = (PayloadType *) node->data;
        if (index == id)
            return pt->clock_rate;
        index++;
    }
    return NULL;
}

void smartphone_enable_codec(CodecType ct, int id, int enabled) {
    PayloadType *pt;
    int index = 0;
    const bctbx_list_t *node = NULL;
    if (ct == CodecTypeAudio)
        node = linphone_core_get_audio_codecs(g_linphonec);
    else if (ct == CodecTypeVideo)
        node = linphone_core_get_video_codecs(g_linphonec);
    else if (ct == CodecTypeText)
        node = linphone_core_get_text_codecs(g_linphonec);
    for (; node != NULL; node = bctbx_list_next(node)) {
        pt = (PayloadType *) node->data;
        if (index == id)
            linphone_core_enable_payload_type(g_linphonec, pt, enabled);
        index++;
    }
}


long smartphone_create_local_player(long windowid) {
    LinphonePlayer *player = linphone_core_create_local_player(g_linphonec, NULL, NULL,
                                                               (void *) windowid);
    return (long) player;

}

void smartphone_player_destroy(long player) {
    linphone_player_destroy((LinphonePlayer *) player);

}

void *SmartphonePlayerEofCallback(LinphonePlayer *obj, void *user_data) {
    ms_warning("smartphone player end of callback");
}

void smartphone_player_open(long player, const char *filename) {
    linphone_player_open((LinphonePlayer *) player, filename, SmartphonePlayerEofCallback, NULL);

}

void smartphone_player_close(long player) {
    linphone_player_close((LinphonePlayer *) player);
}

void smartphone_player_start(long player) {
    linphone_player_start((LinphonePlayer *) player);
}

void smartphone_player_pause(long player) {

    linphone_player_pause((LinphonePlayer *) player);
}
